﻿using DocumentFormat.OpenXml.Bibliography;
using IronPython.Runtime;
using LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.NPOIHelp;
using OneOf.Types;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils
{
    public static class Text
    {
        public static List<TextPiece> SplitToPiecesByRegex(string regex, string source)
        {
            if (string.IsNullOrEmpty(regex)) return new List<TextPiece>();
            if (string.IsNullOrEmpty(source)) return new List<TextPiece>();

            var list = new List<TextPiece>();
            try
            {
                var reg = new Regex(regex);
                var matches = reg.Matches(source);
                if (matches.Count <= 0)
                {
                    list.Add(new TextPiece()
                    {
                        StartIndex = 0,
                        EndIndex = source.Length,
                        IsMartchText = false,
                        SourceText = source,
                        ReplacedText = source,
                    });
                    return list;
                }

                int newStartIndex = 0;
                foreach (Match match in matches)
                {
                    if (match.Index > 0)
                    {
                        var piece = source.Substring(newStartIndex, match.Index - newStartIndex);
                        list.Add(new TextPiece()
                        {
                            StartIndex = newStartIndex,
                            EndIndex = match.Index,
                            IsMartchText = false,
                            SourceText = piece,
                            ReplacedText = piece,
                        });
                    }

                    list.Add(new TextPiece()
                    {
                        StartIndex = match.Index,
                        EndIndex = match.Index + match.Length,
                        IsMartchText = true,
                        SourceText = match.Value,
                    });
                    newStartIndex = match.Index + match.Length;
                }

                if (matches.Count > 0)
                {
                    var lastMatch = matches[matches.Count - 1];
                    if (lastMatch.Index < source.Length)
                    {
                        var nextIndex = lastMatch.Index + lastMatch.Length;
                        var lastPiece = source.Substring(nextIndex);
                        list.Add(new TextPiece()
                        {
                            StartIndex = nextIndex,
                            EndIndex = source.Length,
                            IsMartchText = false,
                            SourceText = lastPiece,
                            ReplacedText = lastPiece,
                        });
                    }
                }

                return list;
            }
            catch
            {
                list.Clear();
                list.Add(new TextPiece()
                {
                    StartIndex = 0,
                    EndIndex = source.Length,
                    IsMartchText = false,
                    SourceText = source,
                    ReplacedText = source,
                });
                return list;
            }
        }

        public static List<TextPiece> SplitToPiecesByRegex(string regex, string source, bool muiltiLines, bool ignoreCase)
        {
            if (string.IsNullOrEmpty(regex)) return new List<TextPiece>();
            if (string.IsNullOrEmpty(source)) return new List<TextPiece>();

            var list = new List<TextPiece>();
            try
            {

                var options = new RegexOptions();
                if (muiltiLines)
                {
                    options |= RegexOptions.Multiline;
                }

                if (ignoreCase)
                {
                    options |= RegexOptions.IgnoreCase;
                }

                var reg = new Regex(regex, options);

                var matches = reg.Matches(source);
                if (matches.Count <= 0)
                {
                    list.Add(new TextPiece()
                    {
                        StartIndex = 0,
                        EndIndex = source.Length,
                        IsMartchText = false,
                        SourceText = source,
                        ReplacedText = source,
                    });
                    return list;
                }

                int newStartIndex = 0;
                foreach (Match match in matches)
                {
                    if (match.Index > 0)
                    {
                        var piece = source.Substring(newStartIndex, match.Index - newStartIndex);
                        list.Add(new TextPiece()
                        {
                            StartIndex = newStartIndex,
                            EndIndex = match.Index,
                            IsMartchText = false,
                            SourceText = piece,
                            ReplacedText = piece,
                        });
                    }

                    list.Add(new TextPiece()
                    {
                        StartIndex = match.Index,
                        EndIndex = match.Index + match.Length,
                        IsMartchText = true,
                        SourceText = match.Value,
                    });
                    newStartIndex = match.Index + match.Length;
                }

                if (matches.Count > 0)
                {
                    var lastMatch = matches[matches.Count - 1];
                    if (lastMatch.Index < source.Length)
                    {
                        var nextIndex = lastMatch.Index + lastMatch.Length;
                        var lastPiece = source.Substring(nextIndex);
                        list.Add(new TextPiece()
                        {
                            StartIndex = nextIndex,
                            EndIndex = source.Length,
                            IsMartchText = false,
                            SourceText = lastPiece,
                            ReplacedText = lastPiece,
                        });
                    }
                }

                return list;
            }
            catch
            {
                list.Clear();
                list.Add(new TextPiece()
                {
                    StartIndex = 0,
                    EndIndex = source.Length,
                    IsMartchText = false,
                    SourceText = source,
                    ReplacedText = source,
                });
                return list;
            }
        }

        public static Match Match(string src, string reg, bool muiltiLine = false)
        {
            if (string.IsNullOrEmpty(src)) return null;

            Regex regex;
            if (muiltiLine)
            {
                regex = new Regex(reg, RegexOptions.Multiline);
            }
            else
            {
                regex = new Regex(reg);
            }

            return regex.Match(src);
        }

        public static MatchCollection Matches(string src, string reg, bool muiltiLine = false)
        {
            if (string.IsNullOrEmpty(src)) return null;

            Regex regex;
            if (muiltiLine)
            {
                regex = new Regex(reg, RegexOptions.Multiline);
            }
            else
            {
                regex = new Regex(reg);
            }

            return regex.Matches(src);
        }

        public static string JoinReplacedList(List<TextPiece> pieces)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var piece in pieces)
                sb.Append(piece.ReplacedText);
            return sb.ToString();
        }

        /// <summary>
        /// 源码来自：https://blog.csdn.net/studyregister/article/details/7076160 ，有修改
        /// 原作者应该是：Sundays
        /// </summary>
        /// <param name="text"></param>
        /// <param name="fontSize"></param>
        /// <param name="fontFamily"></param>
        /// <returns></returns>
        public static double MeasureTextWidth(string text, double fontSize, string fontFamily)
        {
            FormattedText formattedText = new FormattedText(
            text,
            System.Globalization.CultureInfo.InvariantCulture,
            FlowDirection.LeftToRight,
            new Typeface(fontFamily.ToString()),
            fontSize,
            Brushes.Black,
            VisualTreeHelper.GetDpi(Globals.MainWindow).PixelsPerDip);
            return formattedText.WidthIncludingTrailingWhitespace;
        }

        /// <summary>
        /// 取文本宽度。
        /// </summary>
        /// <param name="text">要取宽度的文本</param>
        /// <param name="trimStartAndEnd">是否去除首尾空格。</param>
        /// <returns></returns>
        public static int GetTextWidth(string text, bool trimStartAndEnd = false)
        {
            if (string.IsNullOrEmpty(text)) return 0;

            if (trimStartAndEnd) text = text.Trim();

            //int width = 0;
            //foreach (char c in text)
            //{
            //    width += Encoding.Default.GetByteCount(new char[] { c });//判断全、半角不需要再手工做了。
            //}

            var appendWidth = 0;
            foreach (var c in text)
            {
                // 编码或直接比较字符是行不通的，因为不同编码位置并不完全相同（比如）
                if ("āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüńň".Contains(c))
                    appendWidth++;
            }  // Encoding.Default.GetByteCount() 会将拼音解析为全角宽度！

            return Encoding.Default.GetByteCount(text.ToCharArray()) - appendWidth;  // 注意：不能用 Encoding.UTF8.GetByteCount...
        }

        public static string FatAlphaAndNumbersToThin(string text)
        {
            return ChinesePinYin.FatAlphaAndNumbersToThin(text);
        }

        public static string 转为半角(string text)
        {
            return ChinesePinYin.FatAlphaAndNumbersToThin(text);
        }

        public static string ThinAlphaAndNumbersToFat(string text, bool onlyConvertPunctuation = false)
        {
            return ChinesePinYin.ThinAlphaAndNumbersToFat(text, onlyConvertPunctuation);
        }

        public static string 转为全角(string text, bool onlyConvertPunctuation = false)
        {
            return ChinesePinYin.ThinAlphaAndNumbersToFat(text, onlyConvertPunctuation);
        }

        /// <summary>
        /// 格式化文本中的引号。
        /// </summary>
        /// <param name="text">源文本。</param>
        /// <param name="convertThinQuoters">格式化半角引号。如果为 true ，会将半角单双引号转为全角单双引号。</param>
        /// <returns></returns>
        public static string FormatQuotersInSingleLine(string text, bool convertThinQuoters = false)
        {
            if (string.IsNullOrEmpty(text)) return text;

            var myStr = new StringBuilder();

            var isOpenSingleQuoter = false;
            var isOpenDoubleQuoter = false;

            if (convertThinQuoters)
            {
                foreach (char vChar in text)
                {
                    if (vChar == '\'' || vChar == '‘' || vChar == '’')
                    {
                        if (isOpenSingleQuoter)
                        {
                            myStr.Append('’');
                            isOpenSingleQuoter = false;
                        }
                        else
                        {
                            myStr.Append('‘');
                            isOpenSingleQuoter = true;
                        }
                    }
                    else if (vChar == '\"' || vChar == '“' || vChar == '”')
                    {
                        if (isOpenDoubleQuoter)
                        {
                            myStr.Append('”');
                            isOpenDoubleQuoter = false;
                        }
                        else
                        {
                            myStr.Append('“');
                            isOpenDoubleQuoter = true;
                        }
                    }
                    else
                    {
                        myStr.Append(vChar);
                    }
                }
            }
            else
            {
                foreach (char vChar in text)
                {
                    if (vChar == '‘' || vChar == '’')
                    {
                        if (isOpenSingleQuoter)
                        {
                            myStr.Append('’');
                            isOpenSingleQuoter = false;
                        }
                        else
                        {
                            myStr.Append('‘');
                            isOpenSingleQuoter = true;
                        }
                    }
                    else if (vChar == '“' || vChar == '”')
                    {
                        if (isOpenDoubleQuoter)
                        {
                            myStr.Append('”');
                            isOpenDoubleQuoter = false;
                        }
                        else
                        {
                            myStr.Append('“');
                            isOpenDoubleQuoter = true;
                        }
                    }
                    else
                    {
                        myStr.Append(vChar);
                    }
                }
            }

            if (isOpenSingleQuoter) myStr.Append("’");
            if (isOpenDoubleQuoter) myStr.Append("”");

            return myStr.ToString();
        }

        /// <summary>
        /// 格式化文本中的引号。
        /// </summary>
        /// <param name="text">源文本。</param>
        /// <param name="convertThinQuoters">格式化半角引号。如果为 true ，会将半角单双引号转为全角单双引号。</param>
        /// <returns></returns>
        public static string FormatQuoters(string text, bool convertThinQuoters = false)
        {
            if (string.IsNullOrWhiteSpace(text)) return text;

            var lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);

            var sb = new StringBuilder();

            foreach (var line in lines)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    sb.Append("\r\n");
                    continue;
                }

                sb.Append(FormatQuotersInSingleLine(line, convertThinQuoters) + "\r\n");
            }

            return sb.ToString();
        }

        public static string 格式化引号(string text, bool convertThinQuoters = false)
        {
            return FormatQuoters(text, convertThinQuoters);
        }

        /// <summary>
        /// 取文本宽度。（列定义行宽度为0，只有处理二维文字表时才应调用这个版本。)
        /// </summary>
        /// <param name="text">要取宽度的文本</param>
        /// <param name="trimStartAndEnd">是否去除首尾空格。</param>
        /// <returns></returns>
        public static int GetTextWidth2(string text, bool trimStartAndEnd = false, bool isColumnDefinitionLine = false)
        {
            if (string.IsNullOrEmpty(text)) return 0;
            if (CustomMarkdownSupport.IsColumnAlignmentDefinitionLine(text) && isColumnDefinitionLine) return 0;

            if (trimStartAndEnd) text = text.Trim();

            var appendWidth = 0;
            foreach (var c in text)
            {
                if ("āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüńň".Contains(c))
                    appendWidth++;
            }  // Encoding.Default.GetByteCount() 会将拼音解析为全角宽度！

            return Encoding.Default.GetByteCount(text.ToCharArray()) - appendWidth;    // 注意：不能用 Encoding.UTF8.GetByteCount...
        }

        /// <summary>
        /// 取指定的两个子串之间的文本。
        /// 注意：此方法不会考虑后面还有没有匹配的字串——除非继续从尾标记结束位置向后查找。
        /// </summary>
        /// <param name="header">标头</param>
        /// <param name="tail">标尾</param>
        /// <param name="startIndex">从何位置开始查找。默认值为 0。</param>
        /// <param name="byRegex">是否按正则表达式来查找，默认为 false。</param>
        /// <param name="ignoreCase">是否忽略大小写，默认值为 true。只有在 byRegex 参数为 true 时才有效。</param>
        /// <param name="multiLine">是否跨多行匹配，默认值为 true。只有在 byRegex 参数为 true 时才有意义。</param>
        /// <returns>返回标头、标尾之间的字符串，不含标头、标尾本身。</returns>
        public static string GetSpan(string srcText, string header, string tail, bool byRegex = false,
             int startIndex = 0, bool ignoreCase = true, bool multiLine = true)
        {
            if (string.IsNullOrEmpty(srcText)) return null;
            if (string.IsNullOrEmpty(header)) return null;
            if (string.IsNullOrEmpty(tail)) return null;

            if (srcText.EndsWith("\r\n") == false)
            {
                srcText += "\r\n";
            }

            if (startIndex >= srcText.Length) return null;
            if (startIndex < 0) startIndex = 0;

            if (byRegex == false)
            {
                var indexHeader = srcText.IndexOf(header, startIndex);
                if (indexHeader < startIndex) return null;

                var tailStart = indexHeader + header.Length;
                var indexTail = srcText.IndexOf(tail, tailStart);
                if (indexTail < tailStart) return null;

                var result = srcText.Substring(tailStart, indexTail - tailStart);
                if (string.IsNullOrEmpty(result) == false)
                {
                    result = Regex.Replace(result, @"((?<=[^\r])\n)|(\r(?=[^\n]))|(?<=^)\n", "\r\n");
                }
                return result;
            }
            else
            {
                var regHeaderOptions = new RegexOptions();
                if (multiLine)
                {
                    regHeaderOptions |= RegexOptions.Multiline;
                }

                if (ignoreCase)
                {
                    regHeaderOptions |= RegexOptions.IgnoreCase;
                }
                var regHeader = new Regex(header, regHeaderOptions);

                var matchHeader = regHeader.Match(srcText);
                if (matchHeader.Success == false) return null;

                var regTailOptions = new RegexOptions();
                if (multiLine)
                {
                    regTailOptions |= RegexOptions.Multiline;
                }

                if (ignoreCase)
                {
                    regTailOptions |= RegexOptions.IgnoreCase;
                }
                var regTail = new Regex(tail, regTailOptions);

                var tailStartSearchIndex = matchHeader.Index + matchHeader.Length;
                var matchTail = regTail.Match(srcText, tailStartSearchIndex);
                if (matchTail.Success == false) return null;

                var spanStart = matchHeader.Index + matchHeader.Length;
                if (matchTail.Index < spanStart) return null;

                var result = srcText.Substring(spanStart, matchTail.Index - spanStart);
                if (string.IsNullOrEmpty(result) == false)
                {
                    result = Regex.Replace(result, @"((?<=[^\r])\n)|(\r(?=[^\n]))|(?<=^)\n", "\r\n");
                }
                return result;
            }
        }


        /// <summary>
        /// 取指定的两个子串及之间的文本的相关信息。
        /// 注意：此方法不会考虑后面还有没有匹配的字串——除非继续从尾标记结束位置向后查找。
        /// </summary>
        /// <param name="header">标头</param>
        /// <param name="tail">标尾</param>
        /// <param name="startIndex">从何位置开始查找。默认值为 0。</param>
        /// <param name="byRegex">是否按正则表达式来查找，默认为 false。</param>
        /// <param name="ignoreCase">是否忽略大小写，默认值为 true。只有在 byRegex 参数为 true 时才有效。</param>
        /// <param name="multiLine">是否跨多行匹配，默认值为 true。只有在 byRegex 参数为 true 时才有意义。</param>
        /// <returns>返回标头、标尾及之间的字符串相关信息组成的元组。元组中三个成员均为“纯文本片段”类实例。</returns>
        public static Tuple<纯文本片段, 纯文本片段, 纯文本片段> GetSpanInfo(string srcText, string header, string tail, bool byRegex = false,
             int startIndex = 0, bool ignoreCase = true, bool multiLine = true)
        {
            if (string.IsNullOrEmpty(srcText)) return null;
            if (string.IsNullOrEmpty(header)) return null;
            if (string.IsNullOrEmpty(tail)) return null;

            if (startIndex >= srcText.Length) return null;
            if (startIndex < 0) startIndex = 0;

            if (byRegex == false)
            {
                var indexHeader = srcText.IndexOf(header, startIndex);
                if (indexHeader < startIndex) return null;

                var tailStart = indexHeader + header.Length;
                var indexTail = srcText.IndexOf(tail, tailStart);
                if (indexTail < tailStart) return null;

                var result = srcText.Substring(tailStart, indexTail - tailStart);
                var headInfo = new 纯文本片段()
                {
                    开始索引 = indexHeader,
                    结束索引 = tailStart,
                    源文本片段 = header,
                    是否匹配文本 = true
                };
                var contentInfo = new 纯文本片段()
                {
                    开始索引 = tailStart,
                    结束索引 = indexTail,
                    源文本片段 = result,
                    是否匹配文本 = false,
                };
                var tailInfo = new 纯文本片段()
                {
                    开始索引 = indexTail,
                    结束索引 = indexTail + tail.Length,
                    源文本片段 = tail,
                    是否匹配文本 = true,
                };
                return new Tuple<纯文本片段, 纯文本片段, 纯文本片段>(headInfo, contentInfo, tailInfo);
            }
            else
            {
                var regHeaderOptions = new RegexOptions();
                if (multiLine)
                {
                    regHeaderOptions |= RegexOptions.Multiline;
                }

                if (ignoreCase)
                {
                    regHeaderOptions |= RegexOptions.IgnoreCase;
                }
                var regHeader = new Regex(header, regHeaderOptions);

                var matchHeader = regHeader.Match(srcText, startIndex);
                if (matchHeader.Success == false) return null;

                var regTailOptions = new RegexOptions();
                if (multiLine)
                {
                    regTailOptions |= RegexOptions.Multiline;
                }

                if (ignoreCase)
                {
                    regTailOptions |= RegexOptions.IgnoreCase;
                }
                var regTail = new Regex(tail, regTailOptions);

                var tailStartSearchIndex = matchHeader.Index + matchHeader.Length;
                var matchTail = regTail.Match(srcText, tailStartSearchIndex);
                if (matchTail.Success == false) return null;

                var spanStart = matchHeader.Index + matchHeader.Length;
                if (matchTail.Index < spanStart) return null;

                var result = srcText.Substring(spanStart, matchTail.Index - spanStart);
                var headInfo = new 纯文本片段()
                {
                    开始索引 = matchHeader.Index,
                    结束索引 = spanStart,
                    源文本片段 = matchHeader.Value,
                    是否匹配文本 = true,
                    类型信息 = "头文本",
                };
                var contentInfo = new 纯文本片段()
                {
                    开始索引 = spanStart,
                    结束索引 = matchTail.Index,
                    源文本片段 = result,
                    是否匹配文本 = false,
                    类型信息 = "内容文本",
                };
                var tailInfo = new 纯文本片段()
                {
                    开始索引 = matchTail.Index,
                    结束索引 = matchTail.Index + matchTail.Length,
                    源文本片段 = matchTail.Value,
                    是否匹配文本 = true,
                    类型信息 = "尾文本",
                };
                return new Tuple<纯文本片段, 纯文本片段, 纯文本片段>(headInfo, contentInfo, tailInfo);
            }
        }

        /// <summary>
        /// 此方法用于批量获取一系列按规则集匹配的文本片段。这些规则可以放在 Python 列表中。
        /// 列表中既可以直接使用元组（带三个成员：头规则、尾规则、规则名称）来描述，也可以使用“匹配规则”类实例来描述。
        /// （匹配规则类的好处是语义更清晰，而元组更方便。）
        /// </summary>
        /// <param name="srcText">要在其中获取文本片段的源文本。</param>
        /// <param name="ruleSetList">规则集列表。</param>
        /// <param name="byRegex">规则是否正则表达式。</param>
        /// <param name="startIndex">起始索引。</param>
        /// <param name="ignoreCase">是否忽略大小写。默认为真。</param>
        /// <param name="multiLine">是否支持多行文本。默认为真。</param>
        /// <param name="reversed">是否输出逆序列表（以方便替换）。</param>
        /// <returns></returns>
        public static List<Tuple<纯文本片段, 纯文本片段, 纯文本片段>> GetSpanInfoList(string srcText,
            IronPython.Runtime.PythonList ruleSetList, bool byRegex = false,
            int startIndex = 0, bool ignoreCase = true, bool multiLine = true, bool reversed = false)
        {
            List<Tuple<纯文本片段, 纯文本片段, 纯文本片段>> list = new List<Tuple<纯文本片段, 纯文本片段, 纯文本片段>>();

            foreach (var ruleObject in ruleSetList)
            {
                var rule = ruleObject as IronPython.Runtime.PythonTuple;
                if (rule != null)
                {
                    var startIn = startIndex;

                    var result = GetSpanInfo(srcText, rule[0].ToString(), rule[1].ToString(), byRegex, startIn, ignoreCase, multiLine);

                    while (result != null)
                    {
                        if (rule.Count >= 3 && string.IsNullOrWhiteSpace(rule[2].ToString()) == false)
                        {
                            result.Item1.类型信息 = "头文本";
                            result.Item2.类型信息 = "内容文本";
                            result.Item3.类型信息 = "尾文本";

                            result.Item1.附加信息 = result.Item2.附加信息 = result.Item3.附加信息 = rule[2].ToString();
                        }

                        if (reversed)
                        {
                            list.Insert(0, result);
                        }
                        else
                        {
                            list.Add(result);
                        }

                        startIn = result.Item3.结束索引 + 1;
                        result = GetSpanInfo(srcText, rule[0].ToString(), rule[1].ToString(), byRegex, startIn, ignoreCase, multiLine);
                    }
                    continue;
                }

                var rule2 = ruleObject as 匹配规则;
                if (rule2 != null)
                {
                    var startIn = startIndex;

                    var result = GetSpanInfo(srcText, rule2.头规则, rule2.尾规则, byRegex, startIn, ignoreCase, multiLine);

                    while (result != null)
                    {
                        if (rule.Count >= 3 && string.IsNullOrWhiteSpace(rule[2].ToString()) == false)
                        {
                            result.Item1.类型信息 = "头文本";
                            result.Item2.类型信息 = "内容文本";
                            result.Item3.类型信息 = "尾文本";

                            result.Item1.附加信息 = result.Item2.附加信息 = result.Item3.附加信息 = rule2.规则名称;
                        }

                        if (reversed)
                        {
                            list.Insert(0, result);
                        }
                        else
                        {
                            list.Add(result);
                        }

                        startIn = result.Item3.结束索引 + 1;
                        result = GetSpanInfo(srcText, rule[0].ToString(), rule[1].ToString(), byRegex, startIn, ignoreCase, multiLine);
                    }
                    continue;
                }
            }

            list.Sort(new 纯文本片段排序());

            if (list.Count > 0)
            {
                return list;
            }
            else return null;
        }

        public static string FormatLineSplitter(string text)
        {
            if (string.IsNullOrEmpty(text) == false)
            {
                return Regex.Replace(text, @"((?<=[^\r])\n)|(\r(?=[^\n]))|(?<=^)\n", "\r\n");
            }

            return "";
        }

        /// <summary>
        /// 此方法用于将 list2 中的数据分派到 list1 中。常用于分配任务给某些指定人员。
        /// 例如：有500学生，30老师，需要向每个学生分派一名结对帮扶的老师。
        /// 此时应将学生名册放在 list1 中，老师名册放在 list2 中，然后调用本方法，指定每位老师分派多少学生。
        /// </summary>
        /// <param name="list1"></param>
        /// <param name="list2"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static PythonList 顺序分派数据(PythonList list1, PythonList list2, string splittor = "\t")
        {
            if (list1 == null || list1.Count <= 0)
                throw new Exception("list1 不能为 None 或空列表。");

            if (list2 == null || list2.Count <= 0)
                throw new Exception("list2 不能为 None 或空列表。");

            PythonList result = new PythonList();

            if (list2.Count >= list1.Count)
            {
                for (int i = 0; i < list1.Count; i++)
                {
                    result.Add(list1[i] + splittor + list2[i]);
                }
            }
            else
            {
                var list2Count = list2.Count;

                for (int i = 0; i < list1.Count; i++)
                {
                    var mod = i % list2Count;
                    result.Add(list1[i] + splittor + list2[mod]);
                }
            }

            return result;
        }

        public static PythonList 混淆列表(PythonList list)
        {
            if (list == null || list.Count <= 0)
                throw new Exception("list 不能为 None 或空。");

            int[] randomArray = L.GetRandomIntArray(list.Count);
            var result = new PythonList();
            for (int i = 0; i < randomArray.Length; i++)
            {
                result.Add(list[randomArray[i]]);
            }

            return result;
        }

        public static PythonList 随机分派数据(PythonList list1, PythonList list2, string splittor = "\t")
        {
            if (list1 == null || list1.Count <= 0)
                throw new Exception("list1 不能为 None 或空列表。");

            if (list2 == null || list2.Count <= 0)
                throw new Exception("list2 不能为 None 或空列表。");

            PythonList result = new PythonList();

            list2 = 混淆列表(list2);

            if (list2.Count >= list1.Count)
            {
                for (int i = 0; i < list1.Count; i++)
                {
                    result.Add(list1[i] + splittor + list2[i]);
                }
            }
            else
            {
                var list2Count = list2.Count;

                for (int i = 0; i < list1.Count; i++)
                {
                    var mod = i % list2Count;
                    if (mod == 0)
                        list2 = 混淆列表(list2);
                    result.Add(list1[i] + splittor + list2[mod]);
                }
            }

            return result;
        }

        public static PythonList 文本转双层列表(string srcText, string cellSplittor, bool ignoreBlankLine = true, int spanIgnoreMode = 1, bool trim = true)
        {
            if (string.IsNullOrEmpty(srcText)) throw new Exception("源文本不能为 null 或空字符串。");

            var text = srcText.Trim(new char[] { ' ', '　', '\r', '\n', '\t' });

            if (string.IsNullOrEmpty(text)) throw new Exception("源文本不能为 null 或空字符串，也不能只有全半角空格、制表符、回车符、换行符等空白字符。");

            if (string.IsNullOrEmpty(cellSplittor)) throw new Exception("必须提供行内用于分隔的字符串。此字符串中每个字符都可作为单独的分隔符——本方法不支持字符串本身作为分隔符。");

            var cellSplittorChars = cellSplittor.ToCharArray();

            string[] lines;

            if (ignoreBlankLine)
            {
                lines = srcText.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
            }
            else
            {
                lines = srcText.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.None);
            }

            var result = new PythonList();

            foreach (var line in lines)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    if (ignoreBlankLine == false)  // 这个实际上是整行为空！所以由 ignoreBlankLine 控制。
                    {
                        result.Add(new PythonList());   // 添加空列表
                    }
                }
                else
                {
                    string[] spans;
                    if (spanIgnoreMode <= 1)  // 不移除所有空白片段
                    {
                        spans = line.Split(cellSplittorChars, StringSplitOptions.None);
                    }
                    else
                    {
                        spans = line.Split(cellSplittorChars, StringSplitOptions.RemoveEmptyEntries);
                    }

                    if (trim)
                    {
                        for (int i = 0; i < spans.Length; i++)
                        {
                            spans[i] = spans[i].Trim();   // 移除片段首尾空白字符
                        }
                    }

                    if (spans.Length == 0)
                    {
                        if (ignoreBlankLine == false)
                        {
                            result.Add(new PythonList());    // 空列表
                        }
                    }
                    else if (spans.Length == 1)
                    {
                        if (string.IsNullOrWhiteSpace(spans[0]))
                        {
                            if (spanIgnoreMode <= 0)
                            {
                                var subList = new PythonList();
                                subList.Add(spans[0]);
                                result.Add(subList);
                            }// ==1 时，移除首尾空值，> 1 时移除所有空值。
                            //else if(spanIgnoreMode == 1) ...
                            //else if(spanIgnoreMode > 1) ...  这两种情况不需要处置
                        }
                        else
                        {
                            var subList = new PythonList();
                            subList.Add(spans[0]);
                            result.Add(subList);
                        }
                    }
                    else if (spans.Length > 1)
                    {
                        var subList = new PythonList();

                        for (int i = 0; i < spans.Length; i++)
                        {
                            var span = spans[i];
                            if (string.IsNullOrWhiteSpace(span))
                            {
                                if (spanIgnoreMode <= 0)   // 不移除空值
                                {
                                    subList.Add(span);
                                }
                                else if (spanIgnoreMode == 1)
                                {
                                    // ==1 时，移除首尾空值，其它不移除
                                    if (i > 0 && i < spans.Length - 1)
                                    {
                                        subList.Add(span);
                                    }
                                }
                                // else if (spanIgnoreMode > 1)  // 移除所有空值
                            }
                            else
                            {
                                subList.Add(span);
                            }
                        }

                        if (subList.Count <= 0)
                        {
                            if (ignoreBlankLine == false)
                                result.Add(subList);
                        }
                        else
                        {
                            result.Add(subList);
                        }
                    }
                }
            }

            return result;
        }


        /// <summary>
        /// 将指定文本分解为一维列表。
        /// </summary>
        /// <param name="srcText">源文本。</param>
        /// <param name="cellSplittorList">分割符列表，每个成员都应是一个字符串（非字符串会尝试转换为字符串）。为 null 时为 {"\r\n", "\n", "\r"}。</param>
        /// <param name="spanIgnoreMode">空白忽略模式。为0时，忽略一切空白成员；为1时忽略首尾空白成员；大于1时，忽略所有空白成员。</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static PythonList 文本转列表(string srcText, PythonList cellSplittorList = null, int spanIgnoreMode = 1, bool trim = true)
        {
            if (string.IsNullOrEmpty(srcText)) throw new Exception("源文本不能为 null 或空字符串。");

            var text = srcText.Trim(new char[] { ' ', '　', '\r', '\n', '\t' });

            if (string.IsNullOrEmpty(text)) throw new Exception("源文本不能为 null 或空字符串，也不能只有全半角空格、制表符、回车符、换行符等空白字符。");

            string[] splittors;

            if (cellSplittorList == null || cellSplittorList.Count == 0)
            {
                splittors = new string[] { "\r\n", "\n", "\r" };
            }
            else
            {
                var splittorList = new List<string>();
                foreach (var cell in cellSplittorList)
                {
                    if (cell == null) continue;
                    var cellTxt = cell.ToString();
                    if (string.IsNullOrEmpty(cellTxt) == false)
                    {
                        splittorList.Add(cellTxt);
                    }
                }

                if (splittorList.Count == 0)
                    throw new Exception("提供的分隔符列表无效。");

                splittors = splittorList.ToArray();
            }

            var spans = srcText.Split(splittors, StringSplitOptions.None);

            if (trim)
            {
                for (int i = 0; i < spans.Length; i++)
                {
                    spans[i] = spans[i].Trim();   // 移除片段首尾空白字符
                }
            }

            var result = new PythonList();

            if (spanIgnoreMode < 1)
            {
                // 不忽略空白
                for (int i = 0; i < spans.Length; i++)
                {
                    var span = spans[i];
                    if (trim) span = span.Trim();
                    result.Add(span);
                }
            }
            else if (spanIgnoreMode == 1)
            {
                // 只忽略首尾两个空白，保留其它空白（包括倒数第二个空白元素）

                for (int i = 0; i < spans.Count(); i++)
                {
                    var span = spans[i];
                    if (trim) span = span.Trim();
                    if (string.IsNullOrWhiteSpace(span) == false)
                    {
                        result.Add(span);
                    }
                    else
                    {
                        if (i > 1 && i < spans.Length - 1)
                        {
                            // 非首、尾空白
                            result.Add(span);
                        }
                    }
                }
            }
            else if (spanIgnoreMode > 1)
            {
                for (int i = 0; i < spans.Length; i++)
                {
                    var span = spans[i];
                    if (trim) span = span.Trim();
                    if (string.IsNullOrWhiteSpace(span) == false)
                    {
                        // 只添加非空白片段
                        result.Add(span);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 将从 Word 或 WPSOffice 中复制的纯二维文字表文本，转换为 Html 表格的写法。
        /// 注意：不支持合并单元格。
        /// </summary>
        /// <returns></returns>
        public static string 转成Html表格文本(string srcTxt, bool fstLineIsHeader, string lineSplittor = "\r\n", string cellSplittor = "\t")
        {
            if (string.IsNullOrWhiteSpace(srcTxt)) return "";

            var lines = srcTxt.Split(new string[] { lineSplittor }, StringSplitOptions.RemoveEmptyEntries);
            if (lines.Length <= 0) return "";

            var sb = new StringBuilder();
            sb.Append("..<table>" + lineSplittor);
            for (int i = 0; i < lines.Length; i++)
            {
                var line = lines[i];
                var spans = line.Split(new string[] { cellSplittor }, StringSplitOptions.None);
                if (spans.Length <= 0) continue;

                sb.Append("..    <tr>" + lineSplittor);
                if (fstLineIsHeader && i == 0)
                {
                    foreach (var span in spans)
                    {
                        sb.Append("..        <th>" + span + "</th>" + lineSplittor);
                    }
                }
                else
                {
                    foreach (var span in spans)
                    {
                        sb.Append("..        <td>" + span + "</td>" + lineSplittor);
                    }
                }
                sb.Append("..    </tr>" + lineSplittor);
            }
            sb.Append("..</table>");

            return sb.ToString();
        }
    }

    public class 纯文本片段排序 : IComparer<Tuple<纯文本片段, 纯文本片段, 纯文本片段>>
    {
        public int Compare(Tuple<纯文本片段, 纯文本片段, 纯文本片段> x, Tuple<纯文本片段, 纯文本片段, 纯文本片段> y)
        {
            return x.Item1.开始索引.CompareTo(y.Item1.开始索引);
        }
    }

    public class TextPiece
    {
        public int StartIndex { get; set; }
        public int EndIndex { get; set; }
        public int Length { get { return EndIndex - StartIndex; } }
        public bool IsMartchText { get; set; }
        public string SourceText { get; set; }
        public string ReplacedText { get; set; }
        public List<string> AppendInfos { get; set; } = null;
    }

}
